using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using TerritoryGame.Application.Interfaces;
using TerritoryGame.Domain.Entities.App;
using TerritoryGame.Application.Dtos;
using TerritoryGame.Application.Commands;
using Microsoft.AspNetCore.SignalR;
using TerritoryGame.Api.Hubs;
using Microsoft.Extensions.Logging;

namespace TerritoryGame.Api.Controllers
{
	[ApiController]
	[Route("api/[controller]")]
	[Authorize] // 添加认证要求
	public class RoomsController : ControllerBase
	{
		private readonly IAppGameService _gameService;
		private readonly IAppUserService _userService;
		private readonly IAppUserLevelService _userLevelService;
		private readonly IGameCacheService _cache;
		private readonly IHubContext<GameHub> _hubContext;
		private readonly ILogger<RoomsController> _logger;

		public RoomsController(IAppGameService gameService, IAppUserService userService, IAppUserLevelService userLevelService, IGameCacheService cache, IHubContext<GameHub> hubContext, ILogger<RoomsController> logger)
		{
			_gameService = gameService;
			_userService = userService;
			_userLevelService = userLevelService;
			_cache = cache;
			_hubContext = hubContext;
			_logger = logger;
		}

		/// <summary>
		/// 获取活动房间列表
		/// </summary>
		[HttpGet]
		[AllowAnonymous]
		public async Task<IActionResult> GetActiveRooms()
		{
			try
			{
				var rooms = await _gameService.GetActiveRoomsAsync();
				var result = rooms.Select(r => new
				{
					id = r.Id,
					roomName = r.RoomName,
					maxPlayers = r.MaxPlayers,
					currentPlayers = r.Players?.Count ?? 0,
					status = r.Status.ToString(),
					gameDuration = r.GameDuration,
					creator = r.Creator?.Username,
					createdAt = r.CreatedAt,
					startTime = r.StartTime
				});
				
				return Ok(ApiResult.Success("获取活跃房间列表成功", result));
			}
			catch (Exception ex)
			{
				return StatusCode(500, ApiResult.Failed(500, $"获取活跃房间列表失败: {ex.Message}"));
			}
		}

		/// <summary>
		/// 获取房间详情
		/// </summary>
		[HttpGet("{roomId}")]
		[AllowAnonymous]
		public async Task<IActionResult> GetRoomById(string roomId)
		{
			try
			{
				// 优先从缓存获取（Hub 使用 Redis 作为事实来源），避免只返回内存中的创建者导致列表缺失
				var room = await _cache.GetGameRoomAsync(roomId) ?? await _gameService.GetRoomAsync(roomId);
				if (room == null)
				{
					return NotFound(ApiResult.Failed(404, "房间不存在"));
				}

				// 合并缓存玩家与内存玩家，避免不同入口造成列表缺失（缓存为主）
				var mergedPlayers = new List<Player>();
				try
				{
					if (room.Players != null) mergedPlayers.AddRange(room.Players);
					var cachePlayers = await _cache.GetRoomPlayersAsync(roomId);
					if (cachePlayers != null && cachePlayers.Count > 0)
					{
						foreach (var cp in cachePlayers)
						{
							if (!mergedPlayers.Any(x => x.Id == cp.Id)) mergedPlayers.Add(cp);
						}
					}
				}
				catch { mergedPlayers = room.Players?.ToList() ?? new List<Player>(); }

				// 构建带头像的玩家列表
				var playersWithAvatar = new List<object>();
				foreach (var p in mergedPlayers)
				{
					string? avatar = null;
					string? userNameFromDb = null;
					try
					{
						var userRes = await _userService.GetUserByIdAsync(p.Id);
						if (userRes?.Data is TerritoryGame.Application.Dtos.UserListDto dto)
						{
							avatar = dto.Avatar;
							userNameFromDb = dto.UserName;
						}
					}
					catch { /* 忽略头像/用户名查询失败，保持为null */ }

					var finalName = userNameFromDb ?? p.Username;
					playersWithAvatar.Add(new { id = p.Id, username = finalName, avatar, color = p.Color, areaCount = p.AreaCount, isReady = p.IsReady });
				}

				var result = new
				{
					id = room.Id,
					roomName = room.RoomName,
					maxPlayers = room.MaxPlayers,
					gameDuration = room.GameDuration,
					currentPlayers = playersWithAvatar.Count,
					status = room.Status.ToString(),
					creator = room.Creator?.Username,
					creatorId = room.Creator?.Id,
					creatorName = room.Creator?.Username,
					players = playersWithAvatar,
					createdAt = room.CreatedAt,
					startTime = room.StartTime
				};

				return Ok(ApiResult.Success("获取房间详情成功", result));
			}
			catch (Exception ex)
			{
				return StatusCode(500, ApiResult.Failed(500, $"获取房间详情失败: {ex.Message}"));
			}
		}

		/// <summary>
		/// 创建新房间
		/// </summary>
		[HttpPost]
		public async Task<IActionResult> CreateRoom([FromBody] TerritoryGame.Application.Dtos.CreateRoomRequest request)
		{
			try
			{
				// 调试：检查所有可用的claims
				var allClaims = User.Claims.Select(c => new { c.Type, c.Value }).ToList();
				var userId = User.FindFirst("sub")?.Value ?? 
							User.FindFirst("user_id")?.Value ?? 
							User.FindFirst("uid")?.Value;
				
				if (string.IsNullOrEmpty(userId))
				{
					return Unauthorized(ApiResult.Failed(401, $"用户未认证。可用Claims: {string.Join(", ", allClaims.Select(c => $"{c.Type}={c.Value}"))}"));
				}

				var room = await _gameService.CreateRoomAsync(userId, request.RoomName, request.MaxPlayers, request.GameDuration);
				if (room == null)
				{
					return BadRequest(ApiResult.Failed(400, "创建房间失败"));
				}

				// 同步写入Redis缓存
				await _cache.CacheGameRoomAsync(room);
				if (room.Creator != null)
				{
					await _cache.CachePlayerAsync(room.Id.ToString(), room.Creator);
				}
				await _cache.SetRoomStatusAsync(room.Id.ToString(), room.Status.ToString());
				await _cache.AddOnlineRoomAsync(room.Id.ToString());

				var result = new
				{
					id = room.Id,
					roomName = room.RoomName,
					maxPlayers = room.MaxPlayers,
					creator = room.Creator?.Username,
					status = room.Status.ToString(),
					gameDuration = room.GameDuration,
					createdAt = room.CreatedAt
				};

				return CreatedAtAction(nameof(GetRoomById), new { roomId = room.Id }, ApiResult.Success("房间创建成功", result));
			}
			catch (Exception ex)
			{
				return StatusCode(500, ApiResult.Failed(500, $"创建房间失败: {ex.Message}"));
			}
		}

		/// <summary>
		/// 加入房间
		/// </summary>
		[HttpPost("{roomId}/join")]
		public async Task<IActionResult> JoinRoom(string roomId)
		{
			try
			{
				var userId = User.FindFirst("sub")?.Value ?? 
							User.FindFirst("user_id")?.Value ?? 
							User.FindFirst("uid")?.Value;
				
				if (string.IsNullOrEmpty(userId))
				{
					return Unauthorized(ApiResult.Failed(401, "用户未认证"));
				}

				// 先检查房间是否存在
				var room = await _gameService.GetRoomAsync(roomId);
				if (room == null)
				{
					return BadRequest(ApiResult.Failed(400, "房间不存在"));
				}

				// 检查房间状态
				if (room.Status != GameStatus.Waiting)
				{
					return BadRequest(ApiResult.Failed(400, $"房间状态为 {room.Status}，无法加入"));
				}

				// 检查房间是否已满
				if (room.Players.Count >= room.MaxPlayers)
				{
					return BadRequest(ApiResult.Failed(400, $"房间已满 ({room.Players.Count}/{room.MaxPlayers})"));
				}

				// 幂等：已在房间则直接广播并返回成功
				var existedPlayer = room.Players.FirstOrDefault(p => p.Id.ToString() == userId);
				if (existedPlayer != null)
				{
					// 同步用户名与头像
					string? avatarFromDb = null;
					try
					{
						var userRes = await _userService.GetUserByIdAsync(Guid.Parse(userId));
						if (userRes?.Data is TerritoryGame.Application.Dtos.UserListDto du)
						{
							if (!string.IsNullOrWhiteSpace(du.UserName)) existedPlayer.Username = du.UserName;
							avatarFromDb = du.Avatar;
							await _cache.CachePlayerAsync(roomId, existedPlayer);
							await _cache.CacheGameRoomAsync(room);
						}
					}
					catch { }

					await _hubContext.Clients.Group(roomId).SendAsync("PlayerJoined", new { roomId, player = new { id = existedPlayer.Id, username = existedPlayer.Username, avatar = avatarFromDb, isReady = existedPlayer.IsReady } });
					return Ok(ApiResult.Success("你已经在房间中了"));
				}

				// 使用用户表中的用户名创建玩家实体，避免匿名名
				string finalUserName = $"User_{userId[..Math.Min(6, userId.Length)]}";
				string? avatar = null;
				try
				{
					var userRes = await _userService.GetUserByIdAsync(Guid.Parse(userId));
					if (userRes?.Data is TerritoryGame.Application.Dtos.UserListDto du)
					{
						if (!string.IsNullOrWhiteSpace(du.UserName)) finalUserName = du.UserName;
						avatar = du.Avatar;
					}
				}
				catch { }

				var playerEntity = new Player { Id = Guid.Parse(userId), Username = finalUserName };
				var success = await _gameService.JoinRoomAsync(roomId, playerEntity);
				if (!success)
				{
					return BadRequest(ApiResult.Failed(400, "加入房间失败，请稍后重试"));
				}

				// 更新Redis缓存
				var updatedRoom = await _gameService.GetRoomAsync(roomId);
				if (updatedRoom != null)
				{
					var joined = updatedRoom.Players.FirstOrDefault(p => p.Id.ToString() == userId);
					if (joined != null)
					{
						joined.Username = finalUserName;
						await _cache.CachePlayerAsync(roomId, joined);
					}
					await _cache.CacheGameRoomAsync(updatedRoom);
					await _cache.SetRoomStatusAsync(roomId, updatedRoom.Status.ToString());
				}

				// REST 也广播加入事件（带用户名与头像）
				if (updatedRoom != null)
				{
					var joinedDto = updatedRoom.Players.FirstOrDefault(p => p.Id.ToString() == userId);
					if (joinedDto != null)
					{
						await _hubContext.Clients.Group(roomId).SendAsync("PlayerJoined", new { roomId, player = new { id = joinedDto.Id, username = joinedDto.Username, avatar, isReady = joinedDto.IsReady } });
					}
				}

				return Ok(ApiResult.Success("成功加入房间"));
			}
			catch (Exception ex)
			{
				return StatusCode(500, ApiResult.Failed(500, $"加入房间失败: {ex.Message}"));
			}
		}

		/// <summary>
		/// 离开房间
		/// </summary>
		[HttpPost("{roomId}/leave")]
		public async Task<IActionResult> LeaveRoom(string roomId)
		{
			try
			{
				var userId = User.FindFirst("sub")?.Value ?? 
							User.FindFirst("user_id")?.Value ?? 
							User.FindFirst("uid")?.Value;
				
				if (string.IsNullOrEmpty(userId))
				{
					return Unauthorized(ApiResult.Failed(401, "用户未认证"));
				}

				var success = await _gameService.LeaveRoomAsync(roomId, userId);
				if (!success)
				{
					return BadRequest(ApiResult.Failed(400, "离开房间失败"));
				}

				// 更新Redis缓存
				await _cache.RemovePlayerAsync(roomId, Guid.Parse(userId));
				var roomAfter = await _gameService.GetRoomAsync(roomId);
				if (roomAfter != null)
				{
					await _cache.CacheGameRoomAsync(roomAfter);
					await _cache.SetRoomStatusAsync(roomId, roomAfter.Status.ToString());
					if (roomAfter.Players.Count == 0)
					{
						await _cache.RemoveGameRoomAsync(roomId);
						await _cache.RemoveOnlineRoomAsync(roomId);
					}
				}

				// REST 广播离开事件
				await _hubContext.Clients.Group(roomId).SendAsync("PlayerLeft", new { roomId, playerId = userId });

				return Ok(ApiResult.Success("成功离开房间"));
			}
			catch (Exception ex)
			{
				return StatusCode(500, ApiResult.Failed(500, $"离开房间失败: {ex.Message}"));
			}
		}

		/// <summary>
		/// 设置房间为准备就绪状态（已进入游戏界面）
		/// </summary>
		[HttpPost("{roomId}/ready")]
		public async Task<IActionResult> SetRoomReady(string roomId)
		{
			try
			{
				_logger.LogInformation("SetRoomReady called for room: {RoomId}", roomId);
				
				var userId = User.FindFirst("sub")?.Value ?? 
							User.FindFirst("user_id")?.Value ?? 
							User.FindFirst("uid")?.Value;
				
				if (string.IsNullOrEmpty(userId))
				{
					_logger.LogWarning("User not authenticated for SetRoomReady: {RoomId}", roomId);
					return Unauthorized(ApiResult.Failed(401, "用户未认证"));
				}

				_logger.LogInformation("User {UserId} attempting to set room ready: {RoomId}", userId, roomId);

				var success = await _gameService.SetRoomReadyAsync(roomId);
				if (!success)
				{
					_logger.LogWarning("Failed to set room ready: {RoomId}, success: {Success}", roomId, success);
					return BadRequest(ApiResult.Failed(400, "设置房间准备状态失败"));
				}

				// 获取更新后的房间信息
				var updatedRoom = await _gameService.GetRoomAsync(roomId);
				if (updatedRoom != null)
				{
					// 通过SignalR通知所有玩家房间状态已更新
					await _hubContext.Clients.Group(roomId).SendAsync("RoomMembersUpdated", new
					{
						roomId = roomId,
						members = updatedRoom.Players.Select(p => new
						{
							id = p.Id,
							name = p.Username,
							color = p.Color,
							isReady = p.IsReady,
							isHost = p.Id == updatedRoom.Creator.Id
						}).ToList()
					});

					// 发送房间状态变化事件
					await _hubContext.Clients.Group(roomId).SendAsync("RoomStatusChanged", new
					{
						roomId = roomId,
						status = updatedRoom.Status.ToString(),
						previousStatus = "Waiting"
					});

					_logger.LogInformation("RoomMembersUpdated and RoomStatusChanged events sent for room: {RoomId}", roomId);
				}

				_logger.LogInformation("Room set to ready successfully: {RoomId} by user {UserId}", roomId, userId);
				return Ok(ApiResult.Success("房间已准备就绪"));
			}
			catch (Exception ex)
			{
				_logger.LogError(ex, "Exception in SetRoomReady for room: {RoomId}", roomId);
				return StatusCode(500, ApiResult.Failed(500, $"设置房间准备状态失败: {ex.Message}"));
			}
		}

		/// <summary>
		/// 开始游戏
		/// </summary>
		[HttpPost("{roomId}/start")]
		public async Task<IActionResult> StartGame(string roomId)
		{
			try
			{
				var userId = User.FindFirst("sub")?.Value ?? 
							User.FindFirst("user_id")?.Value ?? 
							User.FindFirst("uid")?.Value;
				
				if (string.IsNullOrEmpty(userId))
				{
					return Unauthorized(ApiResult.Failed(401, "用户未认证"));
				}

				var success = await _gameService.StartGameAsync(roomId);
				if (!success)
				{
					return BadRequest(ApiResult.Failed(400, "开始游戏失败"));
				}

				// 同步到Redis：状态与玩家分数归零
				var room = await _gameService.GetRoomAsync(roomId);
				if (room != null)
				{
					await _cache.CacheGameRoomAsync(room);
					await _cache.SetRoomStatusAsync(roomId, room.Status.ToString());
					foreach (var p in room.Players)
					{
						await _cache.CachePlayerAsync(roomId, p);
						await _cache.UpdatePlayerScoreAsync(roomId, p.Id, 0);
					}

					// 额外广播一次 GameStarted（REST 开始路径），携带开始时间与总秒数
					try
					{
						var totalSeconds = room.GameDuration * 60;
						await _hubContext.Clients.Group(roomId).SendAsync("GameStarted", new
						{
							roomId = room.Id.ToString(),
							duration = totalSeconds,
							startTime = room.StartTime,
							timeLeft = totalSeconds,
							gameStatus = "playing"
						});
					}
					catch { }
				}

				return Ok(ApiResult.Success("游戏开始"));
			}
			catch (Exception ex)
			{
				return StatusCode(500, ApiResult.Failed(500, $"开始游戏失败: {ex.Message}"));
			}
		}

		/// <summary>
		/// 结束游戏
		/// </summary>
		[HttpPost("{roomId}/end")]
		public async Task<IActionResult> EndGame(string roomId)
		{
			try
			{
				var userId = User.FindFirst("sub")?.Value ?? 
							User.FindFirst("user_id")?.Value ?? 
							User.FindFirst("uid")?.Value;
				
				if (string.IsNullOrEmpty(userId))
				{
					return Unauthorized(ApiResult.Failed(401, "用户未认证"));
				}

				var success = await _gameService.EndGameAsync(roomId, userId);
				if (!success)
				{
					return BadRequest(ApiResult.Failed(400, "结束游戏失败"));
				}

				// 计算游戏结果
				var result = await _gameService.CalculateGameResultAsync(roomId);

				// 为所有玩家结算经验
				var playerCount = result.Rankings.Count;
				var awards = new List<object>();
				foreach (var p in result.Rankings)
				{
					var isDraw = result.Winner == null;
					var isWin = !isDraw && result.Winner!.Id == p.Id;
					var gameResult = isDraw ? "draw" : (isWin ? "win" : "lose");

					// 经验计算（与 UserLevelController 中保持一致）
					var baseExperience = 20;
					var timeBonus = Math.Min(result.GameDuration * 3, 90);
					var resultBonus = gameResult == "win" ? 100 : gameResult == "draw" ? 60 : 30;
					var areaBonus = Math.Min(p.AreaCount / 50, 200);
					var durationBonus = result.GameDuration >= 12 ? 50
						: result.GameDuration >= 8 ? 40
						: result.GameDuration >= 5 ? 30
						: result.GameDuration >= 3 ? 20
						: 10;
					var streakBonus = 0; // 未跟踪连胜，默认0
					var playerBonus = playerCount >= 5 ? 40 : playerCount == 4 ? 30 : playerCount == 3 ? 20 : playerCount == 2 ? 10 : 0;
					var totalExp = baseExperience + timeBonus + resultBonus + areaBonus + durationBonus + streakBonus + playerBonus;
					var exp = Math.Min(totalExp, 500);

					var reasonParts = new List<string> { "参与游戏" };
					if (result.GameDuration >= 5) reasonParts.Add($"游戏时长 {result.GameDuration} 分钟");
					reasonParts.Add(gameResult == "win" ? "游戏胜利" : gameResult == "draw" ? "游戏平局" : "游戏参与");
					if (p.AreaCount > 0) reasonParts.Add($"涂色面积 {p.AreaCount} 像素");
					var reason = $"完成游戏 - {string.Join("，", reasonParts)}，获得 {exp} 经验值";

					await _userLevelService.AddExperienceAsync(new AddExperienceDto
					{
						UserId = p.Id,
						Experience = exp,
						Reason = reason
					});

					awards.Add(new { playerId = p.Id, username = p.Username, experience = exp, gameResult });
				}

				// 更新Redis房间状态及过期
				var finishedRoom = await _gameService.GetRoomAsync(roomId);
				if (finishedRoom != null)
				{
					await _cache.CacheGameRoomAsync(finishedRoom);
					await _cache.SetRoomStatusAsync(roomId, finishedRoom.Status.ToString());
					await _cache.SetRoomExpiryAsync(roomId, TimeSpan.FromMinutes(30));
				}

				return Ok(ApiResult.Success("游戏结束，已结算经验", new
				{
					roomId,
					winner = result.Winner?.Username,
					playerCount,
					awards
				}));
			}
			catch (Exception ex)
			{
				return StatusCode(500, ApiResult.Failed(500, $"结束游戏失败: {ex.Message}"));
			}
		}

		/// <summary>
		/// 获取房间当前状态（用于前端时间/状态对齐）
		/// </summary>
		[HttpGet("{roomId}/status")]
		[AllowAnonymous]
		public async Task<IActionResult> GetRoomStatus(string roomId)
		{
			try
			{
				// 优先缓存，其次内存
				var room = await _cache.GetGameRoomAsync(roomId) ?? await _gameService.GetRoomAsync(roomId);
				if (room == null)
				{
					return NotFound(ApiResult.Failed(404, "房间不存在"));
				}

				var totalSeconds = room.GameDuration * 60;
				var timeLeft = 0;
				if (room.Status == GameStatus.Playing && room.StartTime.HasValue)
				{
					var elapsed = (int)Math.Max(0, (DateTime.UtcNow - room.StartTime.Value).TotalSeconds);
					timeLeft = Math.Max(0, totalSeconds - elapsed);
				}
				else if (room.Status == GameStatus.Waiting || room.Status == GameStatus.Ready)
				{
					timeLeft = totalSeconds;
				}
				else
				{
					timeLeft = 0;
				}

				var result = new
				{
					roomId = room.Id,
					status = room.Status.ToString(),
					startTime = room.StartTime,
					duration = totalSeconds,
					timeLeft = timeLeft
				};

				return Ok(ApiResult.Success("获取房间状态成功", result));
			}
			catch (Exception ex)
			{
				return StatusCode(500, ApiResult.Failed(500, $"获取房间状态失败: {ex.Message}"));
			}
		}

		/// <summary>
		/// 获取房间排行榜
		/// </summary>
		[HttpGet("{roomId}/leaderboard")]
		[AllowAnonymous]
		public async Task<IActionResult> GetRoomLeaderboard(string roomId)
		{
			try
			{
				var leaderboard = await _gameService.GetRoomLeaderboardAsync(roomId);
				return Ok(ApiResult.Success("获取房间排行榜成功", leaderboard));
			}
			catch (Exception ex)
			{
				return StatusCode(500, ApiResult.Failed(500, $"获取排行榜失败: {ex.Message}"));
			}
		}

		/// <summary>
		/// 删除房间
		/// </summary>
		[HttpDelete("{roomId}")]
		public async Task<IActionResult> DeleteRoom(string roomId)
		{
			try
			{
				var userId = User.FindFirst("sub")?.Value ?? 
							User.FindFirst("user_id")?.Value ?? 
							User.FindFirst("uid")?.Value;
				
				if (string.IsNullOrEmpty(userId))
				{
					return Unauthorized(ApiResult.Failed(401, "用户未认证"));
				}

				var success = await _gameService.DeleteRoomAsync(roomId);
				if (!success)
				{
					return BadRequest(ApiResult.Failed(400, "删除房间失败"));
				}

				return Ok(ApiResult.Success("房间删除成功"));
			}
			catch (Exception ex)
			{
				return StatusCode(500, ApiResult.Failed(500, $"删除房间失败: {ex.Message}"));
			}
		}
	}
}


